package com.lx.boot.web.convert.serializer;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.lx.annotation.Note;
import com.lx.boot.OS;
import com.lx.boot.cache.util.CacheUtils;
import com.lx.boot.web.convert.DFunction;
import com.lx.boot.web.convert.serializer.DictEnumSerializer.DictEnum;
import com.lx.util.LX;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

import static com.lx.constant.DefaultRedisConstant.RedisPrefix.DICT;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.PARAMETER})
@Documented
@JacksonAnnotationsInside
@Serializer(value = DictSerializer.class,function = DictSerializer.EecoderDFunction.class)
@Note("返回值字典处理器")
public @interface DictSerializer {

    @Note("字典类型")
    String type();

    @Note("指定code字段, 不指定时 获取注解所在字段的值")
    String codeField() default "";

    @Note("使用指定类进行获取")
    Class<? extends DictUtils> dictClass() default DictUtils.class;

    public static class EecoderDFunction implements DFunction<SerializerPara, DictSerializer, Object> {
        @Override
        public Object apply(SerializerPara para, DictSerializer convert) {
            // 获取code值
            String code = null;
            if (LX.isNotEmpty(convert.codeField())){
                code = (String) para.getValue(convert.codeField());
            }else {
                code = (String) para.getValue();
            }
            try {
                return OS.getBean(convert.dictClass()).getDict(convert.type(), code);
            }catch (NoSuchBeanDefinitionException e){
                LX.exMsg("请继承DictUtils, 并注入到spring容器");
                return "";
            }
        }

    }

    @Note("字典缓存类 可以继承并实现loadDict() 或使用setDict()进行设置缓存")
    public abstract class DictUtils {
        @Note("获取缓存key")
        protected String getKey(String type, String code){
            return DICT + type + ":" + code;
        }

        @Note("从缓存中获取字典信息")
        public Object getDict(String type, String code){
            if (LX.isEmpty(type) || LX.isEmpty(code)){
                return "";
            }
            return CacheUtils.get(getKey(type,code),()->{return loadDict(type,code);}, 1, TimeUnit.DAYS);
        }

        @Note("设置字典缓存")
        protected void setDict(String type, String code, Object value){
            CacheUtils.put(getKey(type,code), value, 1, TimeUnit.DAYS);
        }

        @Note("失效字典缓存")
        protected void evictDict(String type, String code){
            CacheUtils.evict(getKey(type,code));
        }

        @Note("加载指定type的字典缓存")
        protected abstract Object loadDict(String type, String code);

    }

}
